home *** CD-ROM | disk | FTP | other *** search
- /*
- * name: bitblt
- *
- * description: copy the source rectangle r in a bitmap sb to the
- * corresponding rectangle with origin p in the destination
- * bitmap db using the optional halftone bitmap hb.
- * (algorithm snarfed from the 1st smalltalk-80 book)
- *
- * synopsis: bitblt (sb, r, db, p, hb, f)
- * struct bitmap *sb;
- * struct rectangle *r;
- * struct bitmap *db;
- * struct point *p;
- * struct bitmap *hb;
- * int f;
- *
- * globals: rightmasks (r)
- * allones (r)
- *
- * calls: merge (merge.c)
- *
- * called by: addobs (addobs.c)
- * screenswap (screenswap.c)
- * newlayer (newlayer.c)
- * background (background.c)
- * lbblt (lbblt.c)
- * rectf (rectf.c)
- */
- #include "layers.h"
-
- unsigned short rightmasks[] = {
- 0x0000,
- 0x0003, 0x000f,
- 0x003f, 0x00ff,
- 0x03ff, 0x0fff,
- 0x3fff, 0xffff
- };
- unsigned short allones = 0xffff;
-
- bitblt (sb, r, db, p, hb, f)
- struct bitmap *sb; /* source bitmap */
- struct rectangle *r; /* source rectangle */
- struct bitmap *db; /* destination bitmap */
- struct point *p; /* point in destination bitmap to start
- operation */
- struct bitmap *hb; /* halftone bitmap */
- int f; /* operation to perform */
- {
- int sourceindex;
- int destindex;
- int sourcedelta;
- int destdelta;
- boolean preload;
- int sx;
- int sy;
- int dx;
- int dy;
- int w;
- int h;
- int startpix;
- int endpix;
- int word;
- int skew;
- int nwords;
- int vdir;
- int hdir;
- int i;
- unsigned short merge ();
- unsigned short t; /* temp for exchanging masks */
- unsigned short prevword;
- unsigned short thisword;
- unsigned short skewword;
- unsigned short mergemask;
- unsigned short mergeword;
- unsigned short destword;
- unsigned short mask1;
- unsigned short mask2;
- unsigned short skewmask;
- unsigned short halftoneword;
-
- /*
- * set w and h
- */
- w = r -> corner.x - r -> origin.x;
- h = r -> corner.y - r -> origin.y;
- if ((w <= 0) || (h <= 0))
- return; /* null range */
- /*
- * calculate sx, sy, dx and dy
- */
- sx = r -> origin.x;
- sy = r -> origin.y;
- dx = p -> x;
- dy = p -> y;
- /*
- * calculate skew and edge masks
- */
- skew = (sx - dx) % pixels_word;
- if (skew < 0)
- skew += pixels_word;
- /*
- * how many bits source gets skewed to right
- */
- startpix = pixels_word - (dx % pixels_word);
- /*
- * how many bits in first word
- */
- mask1 = rightmasks[startpix];
- endpix = pixels_word - ((dx + w - 1) % pixels_word + 1);
- /*
- * how many bits in last word
- */
- mask2 = ~rightmasks[endpix];
- skewmask = (skew == 0 ? 0 : rightmasks[pixels_word - skew]);
- /*
- * determine number of words stored per line
- * merge masks if necessary
- */
- if (w <= startpix) { /* i think this should be <=, not < */
- mask1 = mask1 & mask2;
- mask2 = 0;
- nwords = 1;
- }
- else
- nwords = ((w - startpix - 1) / pixels_word) + 2;
- /*
- * check for possible overlap of source and destination
- */
- hdir = vdir = 1; /* default for no overlap */
- if ((sb == db) && (dy >= sy)) {
- if (dy > sy) { /* have to start at bottom */
- vdir = -1;
- sy = sy + h - 1;
- dy = dy + h - 1;
- }
- else {
- if (dx > sx) {
- /*
- * y's are equal, but x's are backwards
- */
- hdir = -1;
- sx = sx + w - 1;
- /*
- * start at right
- */
- dx = dx + w - 1;
- /*
- * and fix up masks
- */
- skewmask = ~skewmask;
- t = mask1;
- mask1 = mask2;
- mask2 = t;
- }
- }
- }
- /*
- * check if need to reload buffer (i.e., two words of
- * source needed for first word of destination)
- */
- preload = ((sb != null) && ((skew != 0) &&
- ((dx % pixels_word) <= (sx % pixels_word))));
- if (hdir < 0)
- preload = !preload;
- /*
- * calculate starting offsets
- */
- if (sb != null)
- sourceindex = (sy - sb -> bm_rect.origin.y) * sb -> bm_width +
- (sx / pixels_word) -
- (sb -> bm_rect.origin.x / pixels_word);
- else
- sourceindex = 0;
- destindex = (dy - db -> bm_rect.origin.y) * db -> bm_width +
- (dx / pixels_word) -
- (db -> bm_rect.origin.x / pixels_word);
- /*
- * calculate increments from end of one line to start of next
- */
- if (sb != null)
- sourcedelta = (sb -> bm_width * vdir) - ((nwords + (preload ? 1 : 0)) * hdir);
- else
- sourcedelta = 0;
- destdelta = (db -> bm_width * vdir) - (nwords * hdir);
- /*
- * perform the data transfer
- */
- for (i = 1; i <= h; i++) { /* this is the vertical loop */
- if (hb != null) {
- halftoneword = *(hb -> bm_base + (dy % pixels_word));
- dy = dy + vdir;
- }
- else
- halftoneword = allones;
- skewword = halftoneword;
- if (preload) {
- prevword = *(sb -> bm_base + sourceindex);
- /*
- * load the 16-bit shifter
- */
- sourceindex = sourceindex + hdir;
- }
- else
- prevword = 0;
- mergemask = mask1;
- /*
- * here is the inner horizontal loop
- */
- for (word = 1; word <= nwords; word++) {
- if (sb != null) {
- prevword = prevword & skewmask;
- /*
- * pick up next word
- */
- thisword = *(sb -> bm_base + sourceindex);
- skewword = prevword | (thisword & ~skewmask);
- prevword = thisword;
- /*
- * 16-bit rotate (actually, this code will work on 32-bit ints as well)
- */
- skewword = (skewword << skew) | (skewword >> (pixels_word - skew));
- }
- destword = *(db -> bm_base + destindex);
- mergeword = merge ((skewword & halftoneword), destword, f);
- *(db -> bm_base + destindex) = ((mergemask & mergeword) |
- (~mergemask & destword));
- sourceindex = sourceindex + hdir;
- destindex = destindex + hdir;
- if (word == (nwords - 1))
- mergemask = mask2;
- else
- mergemask = allones;
- }
- sourceindex = sourceindex + sourcedelta;
- destindex = destindex + destdelta;
- }
- }